/**
 *    Copyright 2006-2017 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.mybatis.generator.maven;

import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.mybatis.generator.api.ShellCallback;
import org.mybatis.generator.config.*;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.ShellException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.mybatis.generator.internal.ObjectFactory;
import org.mybatis.generator.internal.util.ClassloaderUtility;
import org.mybatis.generator.internal.util.StringUtility;
import org.mybatis.generator.internal.util.messages.Messages;
import org.mybatis.generator.logging.LogFactory;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Goal which generates MyBatis/iBATIS artifacts.
 */
@Mojo(name = "delete", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class MybatisDeleteMojo extends AbstractMojo {

    public static final String MAPPER_FILE = "Mapper.java";//mapper 文件后缀
    public static final String EXAMPLE_FILE = "Example.java";//example 文件后缀
    public static final String MAPPER_XML_FILE = "Mapper.xml";//sqlmap文件后缀
    public static final String JAVA_FILE_SUFFIX = ".java";//java文件后缀
    /**
     * Maven Project.
     */
    @Parameter(property = "project", required = true, readonly = true)
    private MavenProject project;

    /**
     * Output Directory.
     */
    @Parameter(property = "mybatis.generator.outputDirectory", defaultValue = "${project.build.directory}/generated-sources/mybatis-generator", required = true)
    private File outputDirectory;

    /**
     * Location of the configuration file.
     */
    @Parameter(property = "mybatis.generator.configurationFile", defaultValue = "${project.basedir}/src/main/resources/generatorConfig.xml", required = true)
    private File configurationFile;

    /**
     * Specifies whether the mojo writes progress messages to the log.
     */
    @Parameter(property = "mybatis.generator.verbose", defaultValue = "false")
    private boolean verbose;

    /**
     * Specifies whether the mojo overwrites existing files. Default is false.
     */
    @Parameter(property = "mybatis.generator.overwrite", defaultValue = "false")
    private boolean overwrite;

    /**
     * Location of a SQL script file to run before generating code. If null,
     * then no script will be run. If not null, then jdbcDriver, jdbcURL must be
     * supplied also, and jdbcUserId and jdbcPassword may be supplied.
     */
    @Parameter(property = "mybatis.generator.sqlScript")
    private String sqlScript;

    /**
     * JDBC Driver to use if a sql.script.file is specified.
     */
    @Parameter(property = "mybatis.generator.jdbcDriver")
    private String jdbcDriver;

    /**
     * JDBC URL to use if a sql.script.file is specified.
     */
    @Parameter(property = "mybatis.generator.jdbcURL")
    private String jdbcURL;

    /**
     * JDBC user ID to use if a sql.script.file is specified.
     */
    @Parameter(property = "mybatis.generator.jdbcUserId")
    private String jdbcUserId;

    /**
     * JDBC password to use if a sql.script.file is specified.
     */
    @Parameter(property = "mybatis.generator.jdbcPassword")
    private String jdbcPassword;

    /**
     * Comma delimited list of table names to generate.
     */
    @Parameter(property = "mybatis.generator.tableNames")
    private String tableNames;

    /**
     * Comma delimited list of contexts to generate.
     */
    @Parameter(property = "mybatis.generator.contexts")
    private String contexts;

    /**
     * Skip generator.
     */
    @Parameter(property = "mybatis.generator.skip", defaultValue = "false")
    private boolean skip;

    public void execute() throws MojoExecutionException {
        if (skip) {
            getLog().info("MyBatis generator is skipped.");
            return;
        }
        System.err.println("=== start delete codes ===");
        LogFactory.setLogFactory(new MavenLogFactory(this));

        // add resource directories to the classpath.  This is required to support
        // use of a properties file in the build.  Typically, the properties file
        // is in the project's source tree, but the plugin classpath does not
        // include the project classpath.
        List<Resource> resources = project.getResources();
        List<String> resourceDirectories = new ArrayList<String>();
        for (Resource resource : resources) {
            resourceDirectories.add(resource.getDirectory());
        }
        ClassLoader cl = ClassloaderUtility.getCustomClassloader(resourceDirectories);
        ObjectFactory.addResourceClassLoader(cl);

        if (configurationFile == null) {
            throw new MojoExecutionException(
                    Messages.getString("RuntimeError.0")); //$NON-NLS-1$
        }

        List<String> warnings = new ArrayList<String>();

        if (!configurationFile.exists()) {
            throw new MojoExecutionException(Messages.getString(
                    "RuntimeError.1", configurationFile.toString())); //$NON-NLS-1$
        }

        runScriptIfNecessary();

        try {
            ConfigurationParser cp = new ConfigurationParser(
                    project.getProperties(), warnings);
            Configuration config = cp.parseConfiguration(configurationFile);
            startDeleteFile(config);
            getLog().info("======delete file complete======");
        } catch (XMLParserException e) {
            for (String error : e.getErrors()) {
                getLog().error(error);
            }
            throw new MojoExecutionException(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            getLog().error("======delete file error======");
        }
    }

    /**
     * 开始清理文件
     *
     * @param config
     */
    private void startDeleteFile(Configuration config) {
        ShellCallback shellCallback = new DefaultShellCallback(false);
        List<Context> contexts = config.getContexts();
        for (Context context : contexts) {
            try {
                //get table
                List<TableConfiguration> tableConfigurations = context.getTableConfigurations();
                for (TableConfiguration tableConfiguration : tableConfigurations) {
                    String domainObjectName = tableConfiguration.getDomainObjectName();
                    if (StringUtility.stringHasValue(domainObjectName)) {
                        JavaClientGeneratorConfiguration configuration = context.getJavaClientGeneratorConfiguration();
                        File javaDirectory = shellCallback.getDirectory(configuration.getTargetProject(), configuration.getTargetPackage());
                        //delete dao
                        String daoFilePath = javaDirectory.getPath() + File.separator + domainObjectName + MAPPER_FILE;
                        File daoFile = new File(daoFilePath);
                        if (daoFile.exists()) {
                            daoFile.delete();// delete
                            getLog().info(String.format("===delete file:%s====", daoFile.getAbsoluteFile()));
                        }
                        //delete domain
                        JavaModelGeneratorConfiguration modelGeneratorConfiguration = context.getJavaModelGeneratorConfiguration();
                        File modelDirectory = shellCallback.getDirectory(modelGeneratorConfiguration.getTargetProject(), modelGeneratorConfiguration.getTargetPackage());
                        //delete domain & Example
                        String domainFilePath = modelDirectory.getPath() + File.separator + domainObjectName + JAVA_FILE_SUFFIX;
                        String domainExamplePath = modelDirectory.getPath() + File.separator + domainObjectName + EXAMPLE_FILE;
                        File domainFile = new File(domainFilePath);
                        File domainExmapleFile = new File(domainExamplePath);
                        if (domainFile.exists()) {
                            domainFile.delete();
                            getLog().info(String.format("===delete file:%s====", domainFile.getAbsoluteFile()));
                        } else {
                            getLog().info(String.format("===file:%s not exists===", domainFile.getAbsoluteFile()));
                        }
                        if (domainExmapleFile.exists()) {
                            domainExmapleFile.delete();
                            getLog().info(String.format("===delete file:%s====", domainExmapleFile.getAbsoluteFile()));
                        } else {
                            getLog().info(String.format("=== file:%s not exists ====", domainExmapleFile.getAbsoluteFile()));
                        }
                        //delete xml
                        SqlMapGeneratorConfiguration mapGeneratorConfiguration = context.getSqlMapGeneratorConfiguration();
                        File xmlDirectory = shellCallback.getDirectory(mapGeneratorConfiguration.getTargetProject(), mapGeneratorConfiguration.getTargetPackage());
                        String xmlFilePath = xmlDirectory + File.separator + domainObjectName + MAPPER_XML_FILE;
                        File xmlFile = new File(xmlFilePath);
                        if (xmlFile.exists()) {
                            xmlFile.delete();
                            getLog().info(String.format("===delete file:%s====", xmlFile.getAbsoluteFile()));
                        } else {
                            getLog().info(String.format("=== file:%s not exists====", xmlFile.getAbsoluteFile()));
                        }
                    } else {
                        continue;
                    }
                }
            } catch (ShellException e) {
                e.printStackTrace();
            }
        }
        //
    }

    private void runScriptIfNecessary() throws MojoExecutionException {
        if (sqlScript == null) {
            return;
        }

        SqlScriptRunner scriptRunner = new SqlScriptRunner(sqlScript,
                jdbcDriver, jdbcURL, jdbcUserId, jdbcPassword);
        scriptRunner.setLog(getLog());
        scriptRunner.executeScript();
    }

    public File getOutputDirectory() {
        return outputDirectory;
    }
}
